package com.watermark.core.drawer;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;

import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;

import com.watermark.IWaterMark;
import com.watermark.core.filter.WaterMarkFilter;
import com.watermark.core.utils.ScreenUtil;

public abstract class WaterMarkDrawer implements IWaterMark {
    private final static int DEFAULT_TEXT_COLOR = Color.WHITE;
    private final static int DEFAULT_TEXT_SIZE = 14;//sp
    private final static int MARGIN_HEIGHT = 10;
    private final static int MARGIN_WIDTH = 20;
    private final static int MARGIN_MIN = 20;
    /**
     * 文本水印 paint
     */
    private final Paint twmPaint;
    private final Canvas canvas;

    private int tWartMarkBackgroundColor = Color.TRANSPARENT;
    // water mark offset x & y
    private int offsetX = 30;
    private int offsetY = 30;
    // water mark width & height
    private int waterMarkWidth = 0;
    private int waterMarkHeight = 0;
    private int lineSpace = 10;
    private Point previewSize;
    private Object lastMark;

    @Override
    public void setPreviewSize(Point previewSize) {
        this.previewSize = previewSize;
    }

    public WaterMarkDrawer() {
        twmPaint = new Paint();
        twmPaint.setTextSize(ScreenUtil.dp2px(DEFAULT_TEXT_SIZE));
        twmPaint.setColor(DEFAULT_TEXT_COLOR);
        twmPaint.setStyle(Paint.Style.FILL);
        twmPaint.setAntiAlias(true);
        canvas = new Canvas();
        previewSize = ScreenUtil.getScreenPoint();
    }

    @Override
    public void setWartMarkBackgroundColor(@ColorInt int tWartMarkBackgroundColor) {
        this.tWartMarkBackgroundColor = tWartMarkBackgroundColor;
    }

    @Override
    public void setWartMarkTextColor(@ColorInt int tWartMarkTextColor) {
        if (null != twmPaint) twmPaint.setColor(tWartMarkTextColor);
    }

    @Override
    public void setWartMarkTextSize(int textSize) {
        twmPaint.setTextSize(ScreenUtil.dp2px(textSize));
    }

    @Override
    public void setWaterMarkLineSpace(int lineSpace) {
        this.lineSpace = lineSpace;
    }

    /**
     * 设置水印的偏移量
     *
     * @param offsetX x 方向偏移比例 范围：0~1
     * @param offsetY Y 方向偏移比例 范围：0~1
     */
    @Override
    public void setWaterMarkOffset(@FloatRange(from = 0, to = 1) float offsetX,
                                   @FloatRange(from = 0, to = 1) float offsetY) {
        this.offsetX = (int) (offsetX * previewSize.x + 0.5);
        this.offsetY = (int) (offsetY * previewSize.y + 0.5);
    }

    /**
     * 设置水印的偏移量
     *
     * @param offsetX x 方向偏移量
     * @param offsetY Y 方向偏移量
     */
    @Override
    public void setWaterMarkOffset(int offsetX, int offsetY) {
        this.offsetX = offsetX;
        this.offsetY = offsetY;
    }

    /**
     * 设置水印的size
     */
    @Override
    public void setWaterMarkSize(int width, int height) {
        this.waterMarkWidth = width;
        this.waterMarkHeight = height;
    }

    int trans(int v, int dv) {
        return v + MARGIN_MIN + dv - v % (dv);
    }

    @Override
    public Bitmap transMark(String[] marks, int width, int height) {
        int len = null == marks ? 0 : marks.length;
        int spaceSize = len == 0 ? 0 : len - 1;
        Point point = measureText(marks, false);
        // try fix width & height
        width = width > 0 ? width : trans(point.x, MARGIN_WIDTH);
        height = height > 0 ? height : trans(point.y, MARGIN_HEIGHT) + lineSpace * spaceSize;// 行间距
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        canvas.setBitmap(bitmap);
        // draw background color
        canvas.drawColor(tWartMarkBackgroundColor);
        if (len > 0) {
            int sx = (width - point.x) / 2;
            int sy = (height - point.y - lineSpace * spaceSize) / 2;
            // 计算行高
            int lineHeight = point.y / len;
            // draw text
            drawMarkText(canvas, marks, width, sx, sy, lineHeight, twmPaint);
        }
        return bitmap;
    }

    private boolean isSupportAutoLineFeed = false;

    public void enableAutoLineFeed(boolean enable) {
        this.isSupportAutoLineFeed = enable;
    }

    /**
     * 绘制多行文字
     *
     * @param canvas     画布
     * @param marks      水印
     * @param x          首字符左下角点位的x坐标
     * @param y          首字符左下角点位的x坐标
     * @param lineHeight 行高
     * @param paint      画笔
     */
    void drawMarkText(Canvas canvas, String[] marks, int width, float x, float y, float lineHeight, Paint paint) {
        int len = null == marks ? 0 : marks.length;
        if (isSupportAutoLineFeed) {
            StringBuilder buffer = new StringBuilder();
            for (int i = 0; i < len; i++) {
                buffer.append(marks[i]);
                buffer.append("\n");
            }
            TextPaint textPaint = new TextPaint(paint);
            StaticLayout layout = new StaticLayout(buffer.toString(), textPaint, width, Layout.Alignment.ALIGN_NORMAL, 0.85f, 0, true);
            canvas.save();
            canvas.translate(x, y);
            layout.draw(canvas);
            canvas.restore();
        } else {
            for (int i = 0; i < len; i++) {
                String mark = marks[i];
                // 累加 行高 & 行间距
                // 首行只有行高
                y = y + lineHeight + (i == 0 ? 0 : lineSpace);
                canvas.drawText(mark, x, y, paint);
            }
        }
    }

    @Override
    public void setWaterMark(String[] mark) {
        setWaterMark(mark, waterMarkWidth, waterMarkHeight, offsetX, offsetY);
    }

    @Override
    public void setWaterMark(String[] mark, int width, int height) {
        setWaterMark(mark, width, height, offsetX, offsetY);
    }

    /**
     * 设置文字水印
     *
     * @param mark   水印文字
     * @param width  水印画布的宽
     * @param height 水印画布的高
     */
    @Override
    public void setWaterMark(String[] mark, int width, int height, int offsetX, int offsetY) {
        lastMark = mark;
        Bitmap btm = transMark(mark, width, height);
        _setWaterMark(btm, offsetX, offsetY);
    }

    @Override
    public void setWaterMark(Bitmap mark) {
        setWaterMark(mark, offsetX, offsetY);
    }

    /**
     * 设置水印
     *
     * @param mark   水印
     * @param startX 起始位置 x 坐标
     * @param startY 起始位置 y 坐标
     */
    public void setWaterMark(Bitmap mark, int startX, int startY) {
        lastMark = mark;
        _setWaterMark(mark, startX, startY);
    }

    /**
     * 设置水印
     *
     * @param mark   水印
     * @param startX 起始位置 x 坐标
     * @param startY 起始位置 y 坐标
     */
    void _setWaterMark(Bitmap mark, int startX, int startY) {
        WaterMarkFilter filter = new WaterMarkFilter();
        filter.setWaterMark(mark);
        filter.setPosition(startX, startY, 0, 0);
        onAddWaterMarkFilter(filter);
    }

    @Override
    public boolean hasWaterMark() {
        return null != lastMark;
    }


    /**
     * 测量绘制文字所需最小画布的尺寸（即行间距 lineSpace = 0）
     *
     * @param marks 文字
     * @return 画布尺寸
     */
    @Override
    public Point measureText(String[] marks, boolean lineSpace) {
        Rect rect = new Rect();
        if (null == marks || 0 == marks.length) {
            int ts = (int) twmPaint.getTextSize();
            return new Point(ts, ts);
        }
        int len = marks.length;
        int x = 0, y = 0;
        for (int i = 0; i < len; i++) {
            String mark = marks[i];
            twmPaint.getTextBounds(mark, 0, mark.length(), rect);
            x = Math.max(x, rect.width());
            y += rect.height();
        }
        // 计算包含行间距
        if (lineSpace) {
            y += (len - 1) * this.lineSpace;
        }
        return new Point(x, y);
    }


    @Override
    public void drawWaterMark(Canvas canvas) {
        if (null != canvas && null != lastMark) {
            // 水印等比缩放
            float scx = 1.0f * canvas.getWidth() / previewSize.x;
            float scy = 1.0f * canvas.getHeight() / previewSize.y;
            if (lastMark instanceof String[]) {
                Paint paint = new Paint(twmPaint);
                String[] marks = (String[]) lastMark;
                int len = null == marks ? 0 : marks.length;
                int spaceSize = len == 0 ? 0 : len - 1;
                Point point = measureText(marks, false);
                int width = waterMarkWidth > 0 ? waterMarkWidth : trans(point.x, MARGIN_WIDTH);
                int height = waterMarkHeight > 0 ? waterMarkHeight : trans(point.y, MARGIN_HEIGHT) + spaceSize * lineSpace;
                Rect rect = scaleRect(width, height, scx, scy);
                // draw rect background
                paint.setColor(tWartMarkBackgroundColor);
                canvas.drawRect(rect, paint);
                // draw text
                if (len > 0) {
                    paint.setColor(twmPaint.getColor());
                    paint.setTextSize(twmPaint.getTextSize() * Math.min(scx, scy));
                    float x = (width - point.x) * scx / 2;
                    float y = (height - point.y - lineSpace * spaceSize) * scy / 2;
                    float lineHeight = point.y * scy / len;
                    drawMarkText(canvas, marks, (int) (width * scx + 0.5f), rect.left + x, rect.top + y, lineHeight, paint);
                }
            } else if (lastMark instanceof Bitmap) {// draw bitmap
                Bitmap mark = (Bitmap) lastMark;
                Rect rect = scaleRect(mark.getWidth(), mark.getHeight(), scx, scy);
                canvas.drawBitmap(mark, null, rect, null);
            }
        }
    }

    Rect scaleRect(int width, int height, float sx, float sy) {
        Rect rect = new Rect();
        rect.left = (int) (offsetX * sx + 0.5f);
        rect.right = (int) ((offsetX + width) * sx + 0.5f);
        rect.top = (int) (offsetY * sy + 0.5f);
        rect.bottom = (int) ((offsetY + height) * sy + 0.5f);
        return rect;
    }

    abstract void onAddWaterMarkFilter(WaterMarkFilter filter);
}
